#pragma once

#include "ILogger.h"
#include "Thread.h"
#include "SimpleCriticalSection.h"

namespace RoomFW {

//
// Method:	G_LOG_X
//
// Description:	Log macros to log to the global logger.  Don't use these directly.
//				Instead, use the next sets of macros that include verbosity in the macro name.
//
// Parameters:
//
//	verbosity - LoggingVerbosity
//
//	format - printf format string
//
//	argx - printf argument.
//
// Return:	None.
//
/** \name G_LOG_X
 * Log macros to log to the global logger.  Don't use these directly.
 * Instead, use the next sets of macros that include verbosity in the macro name.  See also \ref G_LOG_X_VERBOSITY.
 */
//@{
#define G_LOGGER (RoomFW::SimpleLogger::Instance())
#define G_IS_LOGGING (G_LOGGER.isRunning())
#define G_LOG_0(verbosity, format) if (G_IS_LOGGING) LOG_0(&G_LOGGER, verbosity, format)
#define G_LOG_1(verbosity, format, arg1) if (G_IS_LOGGING) LOG_1(&G_LOGGER, verbosity, format, arg1)
#define G_LOG_2(verbosity, format, arg1, arg2) if (G_IS_LOGGING) LOG_2(&G_LOGGER, verbosity, format, arg1, arg2)
#define G_LOG_3(verbosity, format, arg1, arg2, arg3) if (G_IS_LOGGING) LOG_3(&G_LOGGER, verbosity, format, arg1, arg2, arg3)
#define G_LOG_4(verbosity, format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING) LOG_4(&G_LOGGER, verbosity, format, arg1, arg2, arg3, arg4)
#define G_LOG_5(verbosity, format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING) LOG_5(&G_LOGGER, verbosity, format, arg1, arg2, arg3, arg4, arg5)
#define G_LOG_6(verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING) LOG_6(&G_LOGGER, verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6)
#define G_LOG_7(verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING) LOG_7(&G_LOGGER, verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define G_LOG_8(verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING) LOG_8(&G_LOGGER, verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define G_LOG_9(verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING) LOG_9(&G_LOGGER, verbosity, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
#if defined(G_N0_METHOD_TRACE)
	#define G_TRACE_METHOD(method)
#else
	#define G_TRACE_METHOD(method) MethodTracer thisMethodTracer(&G_LOGGER, #method);
#endif
//@}

/**
 * \defgroup G_LOG_X_VERBOSITY Simple Logger Overview
 * Log macros to log to the global logger with compile-time verbosity control.
 *
 * This is the first of 3 updates to the Logging infrastructure.  This one 
 * is fairly simple.  Please read on.
 * 
 * The purpose of this change is to allow selected logging to be removed at 
 * compile-time for better performance.
 *
 * Here's how it works:
 *  -# New macros have been added to RoomFW/SimpleLogger.h that include 
 *    verbosity in the macro name rather than as a parameter.  So to update, 
 *    you might, for example, search and replace 
 *    "G_LOG_3(RoomFW::LV_ERROR, " with "G_LOG_3_ERROR(".
 *  -# The definition of the new macros is controlled by another set of 
 *    macros.  So you might, for example, add "#define G_N0_LV_TRACE" to a 
 *    library's stdafx.h once you are done debugging that library.
 * 
 * The following are guidelines for selection of logging verbosity:
 * 
 * - G_LOG_X_ERROR - Use this to record a definite error.
 * - G_LOG_X_WARNING    - Use this to record something that is of concern, 
 * but not necessarily a show stopper.
 * - G_LOG_X_SYSTEM - Use this to record info that would be useful even 
 * without detailed knowledge of the code.  For example, "schedule 
 * successfully loaded".
 * - G_LOG_X_SOFTWARE  - Use this to record info that is generally useful for 
 * debugging, but doesn't require extremely in-depth knowledge to 
 * understand.  The guideline here might be that any developer on the 
 * project should be able to make some sense of it.
 * - G_LOG_X_TRACE  - Use this for extremely detailed info that is only 
 * useful with in-depth understanding of a specific component.
 * - G_LOG_X_MESSAGE - This is for the framework.  Don't use it.  The third 
 * installment will cover updates to control port logging.  Stay tuned...
 * 
 * Once a library has been debugged, it might be a good idea to define
 * G_N0_LV_TRACE in that library's stdafx.h, to remove unnecessary overhead.
 * 
 * Runtime Logging configuration has been moved to a new key and verbosity is now configurable.
 * See the ConfigurationEditor key $Configuration/MachineControl/Logging to control the
 * LogVerbosityX keys (where X is a memeber of {Error, Message, Software, System, Trace, Warning}.
 *
 * Finally, we can selectively disable the automatic logging of messages on a per port basis.
 * The motivation for this is the ungodly volume of logging we get from the messaging between 
 * the Robot and CanWrapper and the potential performance hit as a result.  
 * Not to mention the inconvenience of having to filter the logs all the time and console logging being useless.
 *
 * So the idea was for each ActiveObject to be able to specify whether messages 
 * received on a given port should be logged or not, based on configuration settings.
 *
 * For an example, see 
 *   - the RobotActiveHSM::initializePortLogging function
 *   - the Configuration keys RobotLogCANPort and RobotLogRobotPort.
 */
//
// Method:	G_LOG_X_VERBOSITY
//
// Description:	Log macros to log to the global logger with compile-time verbosity control.
//
// Parameters:
//
//	format - printf format string
//
//	argx - printf argument.
//
// Return:	None.
//

/** \name G_LOG_X_ERROR
 *  Use this to record a definite error.  See also \ref G_LOG_X_VERBOSITY.
 */
//@{
#define G_IS_LOGGING_ERROR (G_IS_LOGGING && G_LOGGER.isLvError())
#if defined(G_NO_LV_ERROR)
	#define G_LOG_0_ERROR
	#define G_LOG_1_ERROR
	#define G_LOG_2_ERROR
	#define G_LOG_3_ERROR
	#define G_LOG_4_ERROR
	#define G_LOG_5_ERROR
	#define G_LOG_6_ERROR
	#define G_LOG_7_ERROR
	#define G_LOG_8_ERROR
	#define G_LOG_9_ERROR
#else
	#define G_LOG_0_ERROR(format) if (G_IS_LOGGING_ERROR) G_LOG_0(RoomFW::LV_ERROR, (format))
	#define G_LOG_1_ERROR(format, arg1) if (G_IS_LOGGING_ERROR) G_LOG_1(RoomFW::LV_ERROR, (format), (arg1))
	#define G_LOG_2_ERROR(format, arg1, arg2) if (G_IS_LOGGING_ERROR) G_LOG_2(RoomFW::LV_ERROR, (format), (arg1), (arg2))
	#define G_LOG_3_ERROR(format, arg1, arg2, arg3) if (G_IS_LOGGING_ERROR) G_LOG_3(RoomFW::LV_ERROR, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_ERROR(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_ERROR) G_LOG_4(RoomFW::LV_ERROR, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_ERROR(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_ERROR) G_LOG_5(RoomFW::LV_ERROR, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_ERROR(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_ERROR) G_LOG_6(RoomFW::LV_ERROR, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_ERROR(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_ERROR) G_LOG_7(RoomFW::LV_ERROR, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_ERROR(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_ERROR) G_LOG_8(RoomFW::LV_ERROR, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_ERROR(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_ERROR) G_LOG_9(RoomFW::LV_ERROR, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}
			
/** \name G_LOG_X_WARNING
 * Use this to record something that is of concern, but not necessarily a show stopper.
 * See also \ref G_LOG_X_VERBOSITY.
 */
//@{
#define G_IS_LOGGING_WARNING (G_IS_LOGGING && G_LOGGER.isLvWarning())
#if defined(G_NO_LV_WARNING)
	#define G_LOG_0_WARNING
	#define G_LOG_1_WARNING
	#define G_LOG_2_WARNING
	#define G_LOG_3_WARNING
	#define G_LOG_4_WARNING
	#define G_LOG_5_WARNING
	#define G_LOG_6_WARNING
	#define G_LOG_7_WARNING
	#define G_LOG_8_WARNING
	#define G_LOG_9_WARNING
#else
	#define G_LOG_0_WARNING(format) if (G_IS_LOGGING_WARNING) G_LOG_0(RoomFW::LV_WARNING, (format))
	#define G_LOG_1_WARNING(format, arg1) if (G_IS_LOGGING_WARNING) G_LOG_1(RoomFW::LV_WARNING, (format), (arg1))
	#define G_LOG_2_WARNING(format, arg1, arg2) if (G_IS_LOGGING_WARNING) G_LOG_2(RoomFW::LV_WARNING, (format), (arg1), (arg2))
	#define G_LOG_3_WARNING(format, arg1, arg2, arg3) if (G_IS_LOGGING_WARNING) G_LOG_3(RoomFW::LV_WARNING, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_WARNING(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_WARNING) G_LOG_4(RoomFW::LV_WARNING, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_WARNING(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_WARNING) G_LOG_5(RoomFW::LV_WARNING, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_WARNING(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_WARNING) G_LOG_6(RoomFW::LV_WARNING, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_WARNING(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_WARNING) G_LOG_7(RoomFW::LV_WARNING, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_WARNING(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_WARNING) G_LOG_8(RoomFW::LV_WARNING, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_WARNING(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_WARNING) G_LOG_9(RoomFW::LV_WARNING, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}

/** @name G_LOG_X_SYSTEM
 * Use this to record info that would be useful even without detailed knowledge of the code.
 *	For example, "schedule successfully loaded".  See also \ref G_LOG_X_VERBOSITY.
 */
//@{
#define G_IS_LOGGING_SYSTEM (G_IS_LOGGING && G_LOGGER.isLvSystem())
#if defined(G_NO_LV_SYSTEM)
	#define G_LOG_0_SYSTEM
	#define G_LOG_1_SYSTEM
	#define G_LOG_2_SYSTEM
	#define G_LOG_3_SYSTEM
	#define G_LOG_4_SYSTEM
	#define G_LOG_5_SYSTEM
	#define G_LOG_6_SYSTEM
	#define G_LOG_7_SYSTEM
	#define G_LOG_8_SYSTEM
	#define G_LOG_9_SYSTEM
#else
	#define G_LOG_0_SYSTEM(format) if (G_IS_LOGGING_SYSTEM) G_LOG_0(RoomFW::LV_SYSTEM, (format))
	#define G_LOG_1_SYSTEM(format, arg1) if (G_IS_LOGGING_SYSTEM) G_LOG_1(RoomFW::LV_SYSTEM, (format), (arg1))
	#define G_LOG_2_SYSTEM(format, arg1, arg2) if (G_IS_LOGGING_SYSTEM) G_LOG_2(RoomFW::LV_SYSTEM, (format), (arg1), (arg2))
	#define G_LOG_3_SYSTEM(format, arg1, arg2, arg3) if (G_IS_LOGGING_SYSTEM) G_LOG_3(RoomFW::LV_SYSTEM, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_SYSTEM(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_SYSTEM) G_LOG_4(RoomFW::LV_SYSTEM, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_SYSTEM(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_SYSTEM) G_LOG_5(RoomFW::LV_SYSTEM, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_SYSTEM(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_SYSTEM) G_LOG_6(RoomFW::LV_SYSTEM, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_SYSTEM(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_SYSTEM) G_LOG_7(RoomFW::LV_SYSTEM, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_SYSTEM(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_SYSTEM) G_LOG_8(RoomFW::LV_SYSTEM, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_SYSTEM(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_SYSTEM) G_LOG_9(RoomFW::LV_SYSTEM, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}

/** \name G_LOG_X_SOFTWARE
 * Use this to record info that is generally useful for
 * debugging, but doesn't require extremely in-depth knowledge to 
 * understand.  The guideline here might be that any developer on the 
 * project should be able to make some sense of it.  See also \ref G_LOG_X_VERBOSITY.
 */
//@{
#define G_IS_LOGGING_SOFTWARE (G_IS_LOGGING && G_LOGGER.isLvSoftware())
#if defined(G_NO_LV_SOFTWARE)
	#define G_LOG_0_SOFTWARE
	#define G_LOG_1_SOFTWARE
	#define G_LOG_2_SOFTWARE
	#define G_LOG_3_SOFTWARE
	#define G_LOG_4_SOFTWARE
	#define G_LOG_5_SOFTWARE
	#define G_LOG_6_SOFTWARE
	#define G_LOG_7_SOFTWARE
	#define G_LOG_8_SOFTWARE
	#define G_LOG_9_SOFTWARE
#else
	#define G_LOG_0_SOFTWARE(format) if (G_IS_LOGGING_SOFTWARE) G_LOG_0(RoomFW::LV_SOFTWARE, (format))
	#define G_LOG_1_SOFTWARE(format, arg1) if (G_IS_LOGGING_SOFTWARE) G_LOG_1(RoomFW::LV_SOFTWARE, (format), (arg1))
	#define G_LOG_2_SOFTWARE(format, arg1, arg2) if (G_IS_LOGGING_SOFTWARE) G_LOG_2(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2))
	#define G_LOG_3_SOFTWARE(format, arg1, arg2, arg3) if (G_IS_LOGGING_SOFTWARE) G_LOG_3(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_SOFTWARE(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_SOFTWARE) G_LOG_4(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_SOFTWARE(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_SOFTWARE) G_LOG_5(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_SOFTWARE(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_SOFTWARE) G_LOG_6(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_SOFTWARE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_SOFTWARE) G_LOG_7(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_SOFTWARE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_SOFTWARE) G_LOG_8(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_SOFTWARE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_SOFTWARE) G_LOG_9(RoomFW::LV_SOFTWARE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}

/** \name G_LOG_X_MESSAGE
 * This is for the framework.  Don't use it.  The third 
 * installment will cover updates to control port logging.  Stay tuned...
 */
//@{
#define G_IS_LOGGING_MESSAGE (G_IS_LOGGING && G_LOGGER.isLvMessage())
#if defined(G_NO_LV_MESSAGE)
	#define G_LOG_0_MESSAGE
	#define G_LOG_1_MESSAGE
	#define G_LOG_2_MESSAGE
	#define G_LOG_3_MESSAGE
	#define G_LOG_4_MESSAGE
	#define G_LOG_5_MESSAGE
	#define G_LOG_6_MESSAGE
	#define G_LOG_7_MESSAGE
	#define G_LOG_8_MESSAGE
	#define G_LOG_9_MESSAGE
#else
	#define G_LOG_0_MESSAGE(format) if (G_IS_LOGGING_MESSAGE) G_LOG_0(RoomFW::LV_MESSAGE, (format))
	#define G_LOG_1_MESSAGE(format, arg1) if (G_IS_LOGGING_MESSAGE) G_LOG_1(RoomFW::LV_MESSAGE, (format), (arg1))
	#define G_LOG_2_MESSAGE(format, arg1, arg2) if (G_IS_LOGGING_MESSAGE) G_LOG_2(RoomFW::LV_MESSAGE, (format), (arg1), (arg2))
	#define G_LOG_3_MESSAGE(format, arg1, arg2, arg3) if (G_IS_LOGGING_MESSAGE) G_LOG_3(RoomFW::LV_MESSAGE, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_MESSAGE(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_MESSAGE) G_LOG_4(RoomFW::LV_MESSAGE, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_MESSAGE(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_MESSAGE) G_LOG_5(RoomFW::LV_MESSAGE, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_MESSAGE(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_MESSAGE) G_LOG_6(RoomFW::LV_MESSAGE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_MESSAGE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_MESSAGE) G_LOG_7(RoomFW::LV_MESSAGE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_MESSAGE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_MESSAGE) G_LOG_8(RoomFW::LV_MESSAGE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_MESSAGE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_MESSAGE) G_LOG_9(RoomFW::LV_MESSAGE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}

/** \name G_LOG_X_TRACE
 * Use this for extremely detailed info that is only 
 * useful with in-depth understanding of a specific component.  See also \ref G_LOG_X_VERBOSITY.
 */
//@{
//
#define G_IS_LOGGING_TRACE (G_IS_LOGGING && G_LOGGER.isLvTrace())
//#if (!defined(_DEBUG) | defined(NDEBUG) | defined(G_N0_LV_TRACE))
#if defined(G_N0_LV_TRACE)
	#define G_LOG_0_TRACE
	#define G_LOG_1_TRACE
	#define G_LOG_2_TRACE
	#define G_LOG_3_TRACE
	#define G_LOG_4_TRACE
	#define G_LOG_5_TRACE
	#define G_LOG_6_TRACE
	#define G_LOG_7_TRACE
	#define G_LOG_8_TRACE
	#define G_LOG_9_TRACE
#else
	#define G_LOG_0_TRACE(format) if (G_IS_LOGGING_TRACE) G_LOG_0(RoomFW::LV_TRACE, (format))
	#define G_LOG_1_TRACE(format, arg1) if (G_IS_LOGGING_TRACE) G_LOG_1(RoomFW::LV_TRACE, (format), (arg1))
	#define G_LOG_2_TRACE(format, arg1, arg2) if (G_IS_LOGGING_TRACE) G_LOG_2(RoomFW::LV_TRACE, (format), (arg1), (arg2))
	#define G_LOG_3_TRACE(format, arg1, arg2, arg3) if (G_IS_LOGGING_TRACE) G_LOG_3(RoomFW::LV_TRACE, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_TRACE(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_TRACE) G_LOG_4(RoomFW::LV_TRACE, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_TRACE(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_TRACE) G_LOG_5(RoomFW::LV_TRACE, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_TRACE(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_TRACE) G_LOG_6(RoomFW::LV_TRACE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_TRACE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_TRACE) G_LOG_7(RoomFW::LV_TRACE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_TRACE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_TRACE) G_LOG_8(RoomFW::LV_TRACE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_TRACE(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_TRACE) G_LOG_9(RoomFW::LV_TRACE, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}

/** \name G_LOG_X_SPEED
 * Use this for logging items to be used for lower verbosity system performance measurements.  See also \ref G_LOG_X_VERBOSITY.
 * \see http://cybertfs.msp.cyberoptics.com/sites/se500/Software%20Design%20Notes/Speed%20Logging.doc
 */
//@{
#define G_IS_LOGGING_SPEED (G_IS_LOGGING && G_LOGGER.isLvSpeed())
#if defined(G_NO_LV_SPEED)
	#define G_LOG_0_SPEED
	#define G_LOG_1_SPEED
	#define G_LOG_2_SPEED
	#define G_LOG_3_SPEED
	#define G_LOG_4_SPEED
	#define G_LOG_5_SPEED
	#define G_LOG_6_SPEED
	#define G_LOG_7_SPEED
	#define G_LOG_8_SPEED
	#define G_LOG_9_SPEED
#else
	#define G_LOG_0_SPEED(format) if (G_IS_LOGGING_SPEED) G_LOG_0(RoomFW::LV_SPEED, (format))
	#define G_LOG_1_SPEED(format, arg1) if (G_IS_LOGGING_SPEED) G_LOG_1(RoomFW::LV_SPEED, (format), (arg1))
	#define G_LOG_2_SPEED(format, arg1, arg2) if (G_IS_LOGGING_SPEED) G_LOG_2(RoomFW::LV_SPEED, (format), (arg1), (arg2))
	#define G_LOG_3_SPEED(format, arg1, arg2, arg3) if (G_IS_LOGGING_SPEED) G_LOG_3(RoomFW::LV_SPEED, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_SPEED(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_SPEED) G_LOG_4(RoomFW::LV_SPEED, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_SPEED(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_SPEED) G_LOG_5(RoomFW::LV_SPEED, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_SPEED(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_SPEED) G_LOG_6(RoomFW::LV_SPEED, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_SPEED(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_SPEED) G_LOG_7(RoomFW::LV_SPEED, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_SPEED(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_SPEED) G_LOG_8(RoomFW::LV_SPEED, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_SPEED(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_SPEED) G_LOG_9(RoomFW::LV_SPEED, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}

/** \name G_LOG_X_SPEED
 * Use this for logging items to be used for higher verbosity development performance measurements.  See also \ref G_LOG_X_VERBOSITY.
 * \see http://cybertfs.msp.cyberoptics.com/sites/se500/Software%20Design%20Notes/Speed%20Logging.doc
 */
//@{
#define G_IS_LOGGING_SPEED2 (G_IS_LOGGING && G_LOGGER.isLvSpeed2())
#if defined(G_NO_LV_SPEED2)
	#define G_LOG_0_SPEED2
	#define G_LOG_1_SPEED2
	#define G_LOG_2_SPEED2
	#define G_LOG_3_SPEED2
	#define G_LOG_4_SPEED2
	#define G_LOG_5_SPEED2
	#define G_LOG_6_SPEED2
	#define G_LOG_7_SPEED2
	#define G_LOG_8_SPEED2
	#define G_LOG_9_SPEED2
#else
	#define G_LOG_0_SPEED2(format) if (G_IS_LOGGING_SPEED2) G_LOG_0(RoomFW::LV_SPEED2, (format))
	#define G_LOG_1_SPEED2(format, arg1) if (G_IS_LOGGING_SPEED2) G_LOG_1(RoomFW::LV_SPEED2, (format), (arg1))
	#define G_LOG_2_SPEED2(format, arg1, arg2) if (G_IS_LOGGING_SPEED2) G_LOG_2(RoomFW::LV_SPEED2, (format), (arg1), (arg2))
	#define G_LOG_3_SPEED2(format, arg1, arg2, arg3) if (G_IS_LOGGING_SPEED2) G_LOG_3(RoomFW::LV_SPEED2, (format), (arg1), (arg2), (arg3))
	#define G_LOG_4_SPEED2(format, arg1, arg2, arg3, arg4) if (G_IS_LOGGING_SPEED2) G_LOG_4(RoomFW::LV_SPEED2, (format), (arg1), (arg2), (arg3), (arg4))
	#define G_LOG_5_SPEED2(format, arg1, arg2, arg3, arg4, arg5) if (G_IS_LOGGING_SPEED2) G_LOG_5(RoomFW::LV_SPEED2, (format), (arg1), (arg2), (arg3), (arg4), (arg5))
	#define G_LOG_6_SPEED2(format, arg1, arg2, arg3, arg4, arg5, arg6) if (G_IS_LOGGING_SPEED2) G_LOG_6(RoomFW::LV_SPEED2, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6))
	#define G_LOG_7_SPEED2(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) if (G_IS_LOGGING_SPEED2) G_LOG_7(RoomFW::LV_SPEED2, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7))
	#define G_LOG_8_SPEED2(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) if (G_IS_LOGGING_SPEED2) G_LOG_8(RoomFW::LV_SPEED2, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8))
	#define G_LOG_9_SPEED2(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) if (G_IS_LOGGING_SPEED2) G_LOG_9(RoomFW::LV_SPEED2, (format), (arg1), (arg2), (arg3), (arg4), (arg5), (arg6), (arg7), (arg8), (arg9))
#endif
//@}

///
/// Class:	SimpleLogger
///
/// Description:	Simple logging thread.  Writes to standard output and/or specified file.
///
/// Author:	Andrew Sage
///
class SimpleLogger : public ILogger, public EventThread
{
public:

	///
	/// Method:	Instance
	///
	/// Description:	Get the single instance of this class.
	///
	/// Parameters:	None.
	///
	/// Return:	Reference to the single instance of this class.
	///
	static SimpleLogger& Instance(void);

	///
	/// Thread override.
	///
	virtual const char* getThreadName() const;

};

}
